/*
 * Copyright (c) 2010-2011 Josef Hardi <josef.hardi@gmail.com>
 * Copyright (c) 2010 Piotr Zagawa <piotr.zagawa@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package id.duapuluhdua.dakidaki.map;

import java.util.List;

/**
 * @author Josef Hardi <josef.hardi@gmail.com>
 */
public class Mercator
{
  /** Constants */
  // Based on WGS-84 (World Geodetic System, 1984).
  final private static double R_MAJOR = 6378137.0;  // Equatorial radius (m).
  final private static double R_MINOR = 6356752.3142;  // Polar radius (m).
  final private static double ECCENTRICITY = Math.sqrt(1.0 - Math.pow(R_MINOR / R_MAJOR, 2));
  final private static double ECCENTRICITY_HALF = 0.5 * ECCENTRICITY;
  final private static double PI_HALF = Math.PI * 0.5;

  /**
   * Retrieve the (x, y) coordinate point from a (longitude, latitude)
   * coordinate point.
   *
   * @param point
   */
  public static void convertToFlat(final GeoPoint point)
  {
    point.mercX = getX(point.wgsLon);
    point.mercY = getY(point.wgsLat);
  }

  /**
   * Retrieve (x, y) coordinate points from a collection of (longitude,
   * latitude) coordinate points.
   *
   * @param points
   */
  public static void convertToFlat(final List<GeoPoint> points)
  {
    for (int i = 0; i < points.size(); i++) {
      GeoPoint point = points.get(i);
      point.mercX = getX(point.wgsLon);
      point.mercY = getY(point.wgsLat);
    }
  }

  public static double getX(double lon)
  {
    return R_MAJOR * Math.toRadians(lon);
  }

  public static double getY(double lat)
  {
    if (lat > 89.5) {
      lat = 89.5;
    }
    if (lat < -89.5) {
      lat = -89.5;
    }

    double phi = Math.toRadians(lat);
    double con = ECCENTRICITY * Math.sin(phi);
    con = Math.pow(((1.0 - con) / (1.0 + con)), ECCENTRICITY_HALF);

    double ts = Math.tan(0.5 * (PI_HALF - phi)) / con;
    double y = 0 - R_MAJOR * Math.log(ts);

    return y;
  }

  /**
   * Simple mercator for square area.
   *
   * @param lat
   * @return
   */
  public static double getSquareY(double lat)
  {
    double latitude = Math.toRadians(lat);
    return R_MAJOR / 2.0 * Math.log( (1.0 + Math.sin(latitude)) / (1.0 - Math.sin(latitude)) );
  }
}
